package cn.jn.lhm.part03;

import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

import static cn.jn.lhm.part01.ByteBufferUtil.debugAll;

/**
 * 基于Selector的Server
 *
 * @author lhm 2753914576@qq.com
 * @time 2023/4/5 - 23:07
 **/
public class Server {
    public static void main(String[] args) throws Exception {
        Selector selector = Selector.open();

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.configureBlocking(false);

        // 注册 Channel 到 Selector上,返回的 SelectionKey 上指定关注的事件,当Selector上有事件时就会触发
        SelectionKey serverKey = ssc.register(selector, 0, null);
        serverKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true) {
            // 当有事件发生时就不会阻塞，不然会阻塞
            selector.select();

            // 发生事件后会添加对于的 SelectionKey 到当前集合中,但是不会主动删除Key
            // 当一个事件被处理后必须从集合中手段移除
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();

                // 说明是连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    SocketChannel client = channel.accept();
                    client.configureBlocking(false);
                    // 将 ByteBuffer 作为一个附件关联到 SelectionKey 上
                    ByteBuffer buffer = ByteBuffer.allocate(10);
                    SelectionKey clientKey = client.register(selector, 0, buffer);
                    clientKey.interestOps(SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    try {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        int read = channel.read(buffer);
                        if (read != -1) {
                            split(buffer);
                        }
                        // 判断是否需要扩容
                        if (buffer.position() == buffer.limit()) {
                            ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2);
                            buffer.flip();
                            newBuffer.put(buffer);
                            // 替换原有的buffer
                            key.attach(newBuffer);
                        }
                    } catch (SocketException e) {
                        e.printStackTrace();
                        // 移除当前的selector中绑定的Channel
                        key.cancel();
                    }
                }

                // 移除当前key
                iterator.remove();
            }
        }
    }


    public static void split(ByteBuffer buffer) {
        buffer.flip();
        for (int i = 0; i < buffer.limit(); i++) {
            if (buffer.get(i) == '\n') {
                int length = i + 1 - buffer.position();
                // 将这条消息存储到新的ByteBuffer中保存起来
                ByteBuffer target = ByteBuffer.allocate(length);

                // 移动position的位置
                for (int j = 0; j < length; j++) {
                    target.put(buffer.get());
                }
                debugAll(target);
            }
        }
        buffer.compact();
    }
}
